package ClassData;

import ClassData.Visitor.IVisitor;
import ClassData.Visitor.IVisitorElement;

/*
import DataFile.Structure_CP_UTF8Info;
*/

public class FieldInfo implements IVisitorElement {

	public static final int ACC_PUBLIC		= 0x0001;	
	public static final int ACC_PRIVATE		= 0x0002;
	public static final int ACC_PROTECTED	= 0x0004;
	public static final int ACC_STATIC		= 0x0008;
	public static final int ACC_FINAL		= 0x0010;
	public static final int ACC_VOLATILE	= 0x0040;
	public static final int ACC_TRANSIENT	= 0x0080;
		
	public static final int FIELD_TYPE_UNKNOWN			= 0;
	public static final int FIELD_TYPE_BYTE				= 1;
	public static final int FIELD_TYPE_CHAR				= 2;
	public static final int FIELD_TYPE_INT				= 3;
	public static final int FIELD_TYPE_FLOAT			= 4;
	public static final int FIELD_TYPE_SHORT			= 5;
	
	public static final int FIELD_TYPE_LONG				= 6;
	public static final int FIELD_TYPE_DOUBLE			= 7;
	public static final int FIELD_TYPE_ARRAY_REFERENCE	= 8;
	public static final int FIELD_TYPE_CLASS_REFERENCE	= 9;
	public static final int FIELD_TYPE_BOOLEAN			= 10;
	
	short access_flags;
	short name_index;
	short descriptor_index;
	byte dataType;
	
	ConstantPoolUtf8_Info fieldName;
	ConstantPoolUtf8_Info fieldDescriptor;
	
	AttributeInfo atributeList[];
	
	/*
	 ACC_PUBLIC  0x0001  Declared public; may be accessed from outside its package.  
	 ACC_PRIVATE  0x0002  Declared private; usable only within the defining class.  
	 ACC_PROTECTED  0x0004  Declared protected; may be accessed within subclasses.  
	 ACC_STATIC  0x0008  Declared static.  
	 ACC_FINAL  0x0010  Declared final; no further assignment after initialization.  
	 ACC_VOLATILE  0x0040  Declared volatile; cannot be cached.  
     ACC_TRANSIENT  0x0080  Declared transient; not written or read by a persistent object manager.
	 */

	/**
	 *  
	 * @param accesFlags acces flags of this field (private, public, static....)
	 * @param nameIndex index to field name in constant pool
	 * @param descriptorIndex index to this field descriptor
	 * 
	 */		
	public FieldInfo(short accesFlags,short nameIndex,short descriptorIndex) {
		access_flags     = accesFlags;
		name_index       = nameIndex;
		descriptor_index = descriptorIndex;	
	}

	public void setFieldName(ConstantPoolUtf8_Info fieldName) {
		this.fieldName = fieldName;
	}

	public String getFieldName() {
		return(fieldName.getString());
	}

	public void setFieldDescriptor(ConstantPoolUtf8_Info fieldDescriptor) {
		this.fieldDescriptor=fieldDescriptor;
	}

	public void setAttributeList(AttributeInfo [] newAtributeList) {
		atributeList=newAtributeList;	
	}

	public byte[] getAsBuffer() {
		byte [] dataBuffer;
	
		dataBuffer= new byte[8];
	
		return(dataBuffer);
	}

	public boolean isStatic() {
		if ((access_flags & ACC_STATIC)>0) return (true);
	
		return(false);
	}

	/**
	 * 
	 * @param constantPool
	 */
	public void parseFieldType(ConstantPool constantPool) {
		ConstantPoolUtf8_Info myConstantInfo;
		myConstantInfo=(ConstantPoolUtf8_Info)constantPool.get(descriptor_index);
		String fieldDescriptor;
	
		if(myConstantInfo.getClass().getName().equals(ConstantPoolUtf8_Info.class.getName())) {
			fieldDescriptor=myConstantInfo.getString();
			
			if (fieldDescriptor.equals("B"))
					dataType=FIELD_TYPE_BYTE;
			
			else  if (fieldDescriptor.equals("C"))
					dataType=FIELD_TYPE_CHAR;	
			
			else if (fieldDescriptor.equals("F"))
				dataType=FIELD_TYPE_FLOAT;
				
			else if  (fieldDescriptor.equals("I"))
				dataType=FIELD_TYPE_INT;
				
			else if (fieldDescriptor.equals("S"))
				dataType=FIELD_TYPE_SHORT;
						
			else if  (fieldDescriptor.equals("Z"))
				dataType=FIELD_TYPE_BOOLEAN;
							
			else if  (fieldDescriptor.startsWith("L"))
				dataType=FIELD_TYPE_CLASS_REFERENCE;
								
			else if  (fieldDescriptor.startsWith("["))
				dataType=FIELD_TYPE_ARRAY_REFERENCE;
		
			else if (fieldDescriptor.equals("D"))
				dataType=FIELD_TYPE_DOUBLE;
			
			else if (fieldDescriptor.equals("J"))
				dataType=FIELD_TYPE_LONG;
			else {
				dataType=FIELD_TYPE_UNKNOWN;
				//TODO Exception !!!!
			}
		}
	}

	/**
	 * 
	 * @return
	 */
	public byte getFieldType() {
		return(dataType);
	}

	/**
	 * 
	 * @return
	 */
	public short getDataSize() {
		switch(dataType) {
			case FIELD_TYPE_BYTE:
			case FIELD_TYPE_BOOLEAN:
				return(1);
			
			case FIELD_TYPE_CHAR:
			case FIELD_TYPE_SHORT:
				return(2);
			
			case FIELD_TYPE_INT:		
			case FIELD_TYPE_FLOAT:
		
			case FIELD_TYPE_ARRAY_REFERENCE:
			case FIELD_TYPE_CLASS_REFERENCE:
		
				return(4);
				
			case FIELD_TYPE_LONG:
			case FIELD_TYPE_DOUBLE:		
				return(8);
				
			default:
				return(0);
		}
	}

	/**
	 * 
	 * @return
	 */
	public short getNameIndex() {
		return(name_index);
	}

	/**
	 * 
	 * @return
	 */
	public short getDescriptorIndex() {
		return(descriptor_index);
	}

	/**
	 * 
	 * @return
	 */
	public short getFlags() {
		return(access_flags);
	}

	/**
	 * 
	 * @return
	 */
	public String getFlagsAsString() {
		String returnString;
		
		returnString="";
		
		if ((access_flags & ACC_PUBLIC) > 0) {
			returnString="public";
		}
		
		if ((access_flags & ACC_PRIVATE) > 0) {
			if (returnString.length() > 0) {
				returnString+=", ";
			}
			returnString+="private";
		}
	
		 if ((access_flags & ACC_PROTECTED) > 0) {
			 if (returnString.length() > 0) {
				returnString+=", ";
			 }
			 returnString+="protected";
		}
	
		if ((access_flags & ACC_STATIC) > 0) {
			if (returnString.length() > 0) {
				returnString+=", ";
			}
			returnString+="static";
		}
	
		if ((access_flags & ACC_FINAL) > 0) {
			if (returnString.length() > 0) {
				returnString+=", ";
			}
			returnString+="final";
		}
	
		if ((access_flags & ACC_VOLATILE) > 0) {
			if (returnString.length() > 0) {
				returnString+=", ";
			}
			returnString+="volatile";
		}
	
		if ((access_flags & ACC_TRANSIENT) > 0) {
			if (returnString.length() > 0) {
				returnString+=", ";
			}
			returnString+="transient";
		}
		
		return(returnString);
	}

	/**
	 * 
	 * @return
	 */
	public short getConstantValueIndex() {
		int counter;
		AttributeInfo_ConstantValue myConstantValue;
		//AttributeInfo test;
		
		for (counter=0;counter<atributeList.length;counter++) {
			if (atributeList[counter].getClass().getName().equals(AttributeInfo_ConstantValue.class.getName())) {
				myConstantValue=(AttributeInfo_ConstantValue)atributeList[counter];
				return(myConstantValue.getIndex());
			}
		}
		
		return(0);
	}

	@Override
	public void receive_Visitor(IVisitor visitor) {
		visitor.visit_FieldInfo(this);
	}
	
}
